#include <stdio.h>
#include <linux/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <semaphore.h>
#include "config.h"
#include "raw_rtp.h"

#if (SOUND_INTERFACE == SOUND_OSS)
#include <sys/soundcard.h>
#elif (SOUND_INTERFACE == SOUND_ALSA)
#include <alsa/asoundlib.h>
#endif

#define MAX_THREAD_COUNT       10  //接收线程数
#define UDP_BIND_PORT_START 20000

AUDIOBUFFER recvbuffer[MAX_THREAD_COUNT][BUFFERNODECOUNT];//每个接收线程占用一个环形缓冲区
AUDIOBUFFER *pWriteHdrRecv[MAX_THREAD_COUNT];
AUDIOBUFFER *pReadHdrRecv[MAX_THREAD_COUNT];
int package_count[MAX_THREAD_COUNT];

//struct timeval last_play_time;//上一次播放时间
struct timeval last_recv_time;//上一次接收时间

AUDIOBUFFER *pReadHdrRecv[MAX_THREAD_COUNT];

AUDIOBUFFER audiobuffer[BUFFERNODECOUNT];
AUDIOBUFFER *pWriteHeader = NULL;
AUDIOBUFFER *pReadHeader = NULL;
int n = 0;//可用包数
int packagesum = 0; //发送或接收总包数
int FrameNO = 0;//帧序号

#if (SOUND_INTERFACE == SOUND_OSS)
int Frequency    = SAMPLERATE;
int format       = AFMT_S16_LE;
int channels     = CHANNELS;
int setting      = 640;
#elif (SOUND_INTERFACE == SOUND_ALSA)
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
#if 0
char *buffer;
#endif
#endif

int flag_capture_audio = 0;
int flag_play_audio    = 0;
int flag_network_send  = 0;
int flag_network_recv  = 0;
int programrun = 1;     //退出程序

pthread_t thread_capture_audio, thread_play_audio, thread_mix_audio;
pthread_t thread_network_send,  thread_network_recv;

sem_t sem_recv;    //接收端用的信号量
sem_t sem_play;    //信号量
sem_t sem_capture; //发送端用的信号量
pthread_mutex_t     mutex_lock;
pthread_mutex_t     mutex_capture;//音频捕获发送互斥

char serverip[15];
int  serverport;

#if (SOUND_INTERFACE == SOUND_ALSA)
int xrun_recovery(snd_pcm_t *handle, int err)
{
   if (err == -EPIPE) {    /* under-run */
      err = snd_pcm_prepare(handle);
   if (err < 0)
      printf("Can't recovery from underrun, prepare failed: %s\n",
         snd_strerror(err));
      return 0;
   } else if (err == -ESTRPIPE) {
      while ((err = snd_pcm_resume(handle)) == -EAGAIN)
         sleep(1);       /* wait until the suspend flag is released */
         if (err < 0) {
            err = snd_pcm_prepare(handle);
         if (err < 0)
            printf("Can't recovery from suspend, prepare failed: %s\n",
              snd_strerror(err));
      }
      return 0;
   }
   return err;
}
#endif

//音频采集线程
void * capture_audio_thread(void *para)
{
    struct timeval tv;
    struct timezone tz;
#if DEBUG_SAVE_CAPTURE_PCM
    FILE *fp = fopen("capture.pcm", "wb");
#endif

#if (SOUND_INTERFACE == SOUND_OSS)
    int fdsound = 0;
    fdsound = open("/dev/dsp", O_RDONLY);
    if(fdsound<0)
    {
       perror("以只写方式打开音频设备");
       return;
    }    

    printf("设置读音频设备参数 setup capture audio device parament\n");
    ioctl(fdsound, SNDCTL_DSP_SPEED, &Frequency);//采样频率
    ioctl(fdsound, SNDCTL_DSP_SETFMT, &format);//音频设备位宽
    ioctl(fdsound, SNDCTL_DSP_CHANNELS, &channels);//音频设备通道
    ioctl(fdsound, SNDCTL_DSP_SETFRAGMENT, &setting);//采样缓冲区

    while(flag_capture_audio)
    {
        if(read(fdsound, &(pWriteHeader->buffer[sizeof(pk_hdr_t)]), sizeof(pWriteHeader->buffer)-sizeof(pk_hdr_t)) < 0)
        {
            perror("读声卡数据");
        }
        else
        {
            sem_post(&sem_capture);        
            gettimeofday(&tv, &tz);
            ((pk_hdr_t*)(pWriteHeader->buffer))->FrameNO = FrameNO++;
            ((pk_hdr_t*)(pWriteHeader->buffer))->sec = tv.tv_sec;
            ((pk_hdr_t*)(pWriteHeader->buffer))->usec = tv.tv_usec;
            printf("capture NO=%5d\n", FrameNO);
            //printf("capture FrameNO=%d,tv_sec; %d ",   FrameNO, tv.tv_sec) ;
            //printf("tv_usec; %d \n", tv.tv_usec);
#if DEBUG_SAVE_CAPTURE_PCM
            fwrite(&(pWriteHeader->buffer[sizeof(pk_hdr_t)]), sizeof(pWriteHeader->buffer)-sizeof(pk_hdr_t), 1, fp);
#endif
            pthread_mutex_lock(&mutex_capture);
            pWriteHeader = pWriteHeader->pNext;
            n++;
            pthread_mutex_unlock(&mutex_capture);
            
            //traceprintf("发送信号量 sem_capture\n");
        }
    }

    close(fdsound);
    printf("音频采集线程已经关闭 audio capture thread is closed\n");
#elif (SOUND_INTERFACE == SOUND_ALSA)
    /* Open PCM device for recording (capture). */
    rc = snd_pcm_open(&handle, "hw:0,0", SND_PCM_STREAM_CAPTURE, 0);
    if (rc < 0) 
    {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
    }
    snd_pcm_hw_params_alloca(&params);/* Allocate a hardware parameters object. */    
    snd_pcm_hw_params_any(handle, params);/* Fill it in with default values. */

    /* Set the desired hardware parameters. */
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);/* Interleaved mode */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);/* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_channels(handle, params, CHANNELS);/* Two channels (stereo), On for mono */
    val = SAMPLERATE;
    snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);/* SAMPLERATE bits/second sampling rate  */
    frames = SAMPLES_FOR_EACH_TIME;
    snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);/* Set period size to SAMPLES_FOR_EACH_TIME frames. */

    /* Write the parameters to the driver */
    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0) 
    {
        fprintf(stderr, "unable to set hw parameters: %s\n",snd_strerror(rc));
        exit(1);
    }

    snd_pcm_hw_params_get_period_size(params, &frames, &dir);/* Use a buffer large enough to hold one period */
#if 0    
    size = frames * sizeof(short) * CHANNELS; /* 2 bytes/sample, 2 channels */
    buffer = (char *) malloc(size);
#endif
    snd_pcm_hw_params_get_period_time(params, &val, &dir);/* We want to loop for 5 seconds */
                                         
    while(flag_capture_audio)
    {
        rc = snd_pcm_readi(handle, &(pWriteHeader->buffer[sizeof(pk_hdr_t)]), frames);
        if (rc == -EPIPE) 
        {
            /* EPIPE means overrun */
            fprintf(stderr, "overrun occurred\n");
            snd_pcm_prepare(handle);
        } 
        else if (rc < 0) 
        {
            fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
        } 
        else if (rc != (int)frames) 
        {
            fprintf(stderr, "short read, read %d frames\n", rc);
        }
                       
#if DEBUG_SAVE_CAPTURE_PCM
        rc = fwrite(pWriteHeader->buffer, frames*sizeof(short), 1, fp);
        if(rc != 1)
        {
            fprintf(stderr, "write error %d\n", rc);
        }
#endif 
        sem_post(&sem_capture);                      
        gettimeofday(&tv, &tz);
        ((pk_hdr_t*)(pWriteHeader->buffer))->FrameNO = FrameNO++;
        ((pk_hdr_t*)(pWriteHeader->buffer))->sec = tv.tv_sec;
        ((pk_hdr_t*)(pWriteHeader->buffer))->usec = tv.tv_usec;
        //printf("capture NO=%5d \n", FrameNO);
        pthread_mutex_lock(&mutex_capture);     
        pWriteHeader = pWriteHeader->pNext;
        n++;                
        pthread_mutex_unlock(&mutex_capture);  
        
        //traceprintf("发送信号量 sem_capture\n");
    }
                                         
    snd_pcm_drain(handle);
    snd_pcm_close(handle);
#if 0    
    free(buffer);
#endif    
#endif

#if DEBUG_SAVE_CAPTURE_PCM
    fclose(fp);
#endif
}

//清除采集线程
void remove_capture_audio(void)
{
    flag_capture_audio = 0;
    usleep(40*1000);
    pthread_cancel(thread_capture_audio);
}

void * network_send_thread(void *p)
{
    struct timeval tv;
    struct timezone tz;
#if DEBUG_SAVE_SEND_PCM
    FILE *fp = fopen("send.pcm", "wb");
#endif
    struct sockaddr_in dest_addr;
    int result;
    int fdsocket = socket(AF_INET, SOCK_DGRAM, 0);
    
    if (fdsocket == -1) 
    {
      perror("socket()");
      //exit(1);
    }
    
    /* 设置远程连接的信息*/
    dest_addr.sin_family = AF_INET;                 /* 注意主机字节顺序*/
    dest_addr.sin_port = htons(serverport);          /* 远程连接端口, 注意网络字节顺序*/
    dest_addr.sin_addr.s_addr = inet_addr(serverip); /* 远程 IP 地址, inet_addr() 会返回网络字节顺序*/
    bzero(&(dest_addr.sin_zero), 8);                /* 其余结构须置 0*/    
    
    printf("数据发送开始\n");
    while(flag_network_send)
    {
        sem_wait(&sem_capture);//等待采集线程有数据
        if(n > 0)
        {      
            //traceprintf("等待 sem_capture 信号量\n");
            result = sendto(fdsocket, pReadHeader->buffer, sizeof(pReadHeader->buffer), 0, (struct sockaddr*)&dest_addr, sizeof(struct sockaddr));
	        if(-1 == result)
	        {
		        perror("数据发送");
	        }
	        else
	        {
                printf("n=%3d ", n);
	            printf("   send NO:%5d \n", ((pk_hdr_t*)(pReadHeader->buffer))->FrameNO);
                gettimeofday (&tv , &tz);
                //printf("   send NO:%5d \n", FrameNO++);
                //printf("send tv_sec %ld ",    tv.tv_sec) ;
                //printf("tv_usec %ld \n", tv.tv_usec);
                //traceprintf("共发送%d数据包\n", packagesum++);
#if DEBUG_SAVE_SEND_PCM
                fwrite(&(pReadHeader->buffer[sizeof(pk_hdr_t)]), sizeof(pReadHeader->buffer)-sizeof(pk_hdr_t), 1, fp);
#endif
                //traceprintf("n=%d, 发送%d字节\n", n, result);
                pthread_mutex_lock(&mutex_capture);                
                pReadHeader = pReadHeader->pNext;
                n--;
                pthread_mutex_unlock(&mutex_capture);	        		        
	        }
	    }
    }
    
    printf("数据发送线程已经关闭 data send thread is closed\n");
    close(fdsocket);
#if DEBUG_SAVE_SEND_PCM
    fclose(fp);
#endif
}

//清除发送线程
void remove_network_send()
{
    flag_network_send = 0;
    usleep(40*1000);
    pthread_cancel(thread_network_send);  
}

void * network_recv_thread(void *p)
{
#if DEBUG_SAVE_RECV_PCM
    FILE *fp = NULL;
    char filename[100];
#endif
    int val;
    struct timeval tv;
    struct timezone tz;
    struct sockaddr_in local_addr, remote_addr;
    int result;
    int socklen;
    int fdsocket = socket(AF_INET, SOCK_DGRAM, 0);
    int i;
    
    if (fdsocket == -1) 
    {
      perror("socket()");
      //exit(1);
    }
    
    printf("bind port = %d, 数据接收开始\n", *((int*)p));
    /* 设置远程连接的信息*/
    local_addr.sin_family = AF_INET;                 /* 注意主机字节顺序*/
    local_addr.sin_port = htons(*((int*)p));          /* 远程连接端口, 注意网络字节顺序*/
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* 远程 IP 地址, inet_addr() 会返回网络字节顺序*/
    bzero(&(local_addr.sin_zero), 8);                /* 其余结构须置 0*/    
    i = *((int*)p) - UDP_BIND_PORT_START;
    bind(fdsocket, (struct sockaddr*)&local_addr, sizeof(struct sockaddr));
    
#if DEBUG_SAVE_RECV_PCM 
    sprintf(filename, "recv_%d.pcm", i); 
    fp = fopen(filename, "wb");
#endif
    //printf("数据接收开始\n");
    while(flag_network_recv)
    {
        //if(n > 3)
        {      
	    //if(-1 == sendto(fdsocket, pReadHeader->buffer, sizeof(pReadHeader->buffer), 0, (struct sockaddr*)&dest_addr, sizeof(struct sockaddr)))
	    socklen = sizeof(struct sockaddr);
	    result = recvfrom(fdsocket, pWriteHdrRecv[i]->buffer, sizeof(pWriteHdrRecv[i]->buffer), 0, (struct sockaddr*)&remote_addr, &socklen);
	    if(result == -1)
	    {
		    perror("数据接收");
	    }
	    else
	    {
            printf("thread%d  recv NO=%5d\n", i, ((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->FrameNO);
#if 0
            printf("recv sec; %ld,",    ((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->sec) ;
            printf("usec; %ld,last_play_time.sec=%ld,usec=%ld ", ((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->usec,
                last_play_time.tv_sec, last_play_time.tv_usec);
            
            val = (((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->sec  - last_play_time.tv_sec)*1000 
                + (((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->usec - last_play_time.tv_usec)/1000;
            printf("val=%d\n", val);
#endif
            sem_post(&sem_recv);

            pthread_mutex_lock(&mutex_lock);
            last_recv_time.tv_sec  = ((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->sec;
            last_recv_time.tv_usec = ((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->usec;
            //traceprintf("共接收%d数据包\n", packagesum++);
            //((pk_hdr_t*)(pWriteHeader->buffer))->sec = tv.tv_sec;
            //((pk_hdr_t*)(pWriteHeader->buffer))->usec = tv.tv_usec;

            //gettimeofday (&tv , &tz);
            //printf("send tv_sec; %llx ",    tv.tv_sec) ;
            //printf("tv_usec; %llx \n", tv.tv_usec);
#if DEBUG_SAVE_RECV_PCM
            fwrite(&(pWriteHdrRecv[i]->buffer[sizeof(pk_hdr_t)]), sizeof(pWriteHdrRecv[i]->buffer)-sizeof(pk_hdr_t), 1, fp);
#endif        
            ((pk_hdr_t*)(pWriteHdrRecv[i]->buffer))->valid = 1;
		    //traceprintf("收到数据 %d byte, n=%d\n", result, n+1);
		    pWriteHdrRecv[i] = pWriteHdrRecv[i]->pNext;
		    package_count[i]++;
            pthread_mutex_unlock(&mutex_lock);
	    }
	    }
    }
    
    printf("数据接收线程已经关闭 data recv thread is closed\n");
#if DEBUG_SAVE_RECV_PCM
    fclose(fp);
#endif
    close(fdsocket);    
}

//清除接收线程
void remove_network_recv()
{
}

void * mix_audio_thread(void *p)
{
    int i, j;
    short *tmp[MAX_THREAD_COUNT];
#if DEBUG_SAVE_MIX_PCM
    FILE *fpmix = fopen("mix.pcm", "wb");
#endif
    
    while(1)
    {
        sem_wait(&sem_recv);

        pthread_mutex_lock(&mutex_lock);
#if 0
        printf("package_count[0]=%d\n", package_count[0]);
        if((package_count[0] > 0) && (((pk_hdr_t*)(pReadHdrRecv[0]->buffer))->valid == 1))
        {
            memcpy(&(pWriteHeader->buffer[0]), &(pReadHdrRecv[0]->buffer[0]), sizeof(pReadHdrRecv[i]->buffer));
            package_count[0]--;
            pReadHdrRecv[0] = pReadHdrRecv[0]->pNext; 
            pWriteHeader = pWriteHeader->pNext;
            pthread_mutex_unlock(&mutex_lock);
            sem_post(&sem_play);
        }
        else
        {
            pthread_mutex_unlock(&mutex_lock);
        }
#else
        memset(pWriteHeader->buffer, 0, sizeof(pWriteHeader->buffer));

        short *t = (short*)&(pWriteHeader->buffer[sizeof(pk_hdr_t)]);        

        for(i=0;i<MAX_THREAD_COUNT;i++)
        {
            if(package_count[i] > 0)
            {
                #if 0
                printf("package_count[%d]=%d,", i, package_count[i]);
                #endif
            }
            tmp[i] = (short*)&(pReadHdrRecv[i]->buffer[sizeof(pk_hdr_t)]);
        }
        printf("\n");

        //printf("(sizeof(pReadHdrRecv[i]->buffer) - sizeof(pk_hdr_t))/2=%d\n", (sizeof(pReadHdrRecv[i]->buffer) - sizeof(pk_hdr_t))/2);
        for(j=0;j<320;j++)        
        {
            for(i=0;i<MAX_THREAD_COUNT;i++)        
            {
                if((package_count[i] > 0)//该线程有数据包
                    && (((pk_hdr_t*)(pReadHdrRecv[i]->buffer))->valid == 1))
                {
                    //printf("i=%d 有\n", i);
                    t[j] += tmp[i][j];
                }
            }
        }
        
#if DEBUG_SAVE_MIX_PCM
        fwrite(t, 640, 1, fpmix);
#endif

        memcpy(pWriteHeader->buffer, pReadHdrRecv[0]->buffer, sizeof(pk_hdr_t));
        for(i=0;i<MAX_THREAD_COUNT;i++)
        {
            if((package_count[i] > 0) && (((pk_hdr_t*)(pReadHdrRecv[0]->buffer))->valid == 1))
            {
                package_count[i]--;
                pReadHdrRecv[i] = pReadHdrRecv[i]->pNext; 
            }
        }

        pWriteHeader = pWriteHeader->pNext;
        pthread_mutex_unlock(&mutex_lock);
        sem_post(&sem_play);
#endif
    }

#if DEBUG_SAVE_MIX_PCM
    fclose(fpmix);
#endif
}

//音频播放线程
void * play_audio_thread(void *para)
{
    int val;
    int i;
#if DEBUG_SAVE_PLAY_PCM
    FILE *fp = fopen("play.pcm", "wb");
#endif

#if (SOUND_INTERFACE == SOUND_OSS)
    int fdsoundplay = 0;
    fdsoundplay = open("/dev/dsp", O_WRONLY);/*只写方式打开设备*/
    if(fdsoundplay<0)
    {
       perror("以只写方式打开音频设备");
       return;
    }


    printf("设置写音频设备参数 setup play audio device parament\n");
    ioctl(fdsoundplay, SNDCTL_DSP_SPEED, &Frequency);//采样频率
    ioctl(fdsoundplay, SNDCTL_DSP_SETFMT, &format);//音频设备位宽
    ioctl(fdsoundplay, SNDCTL_DSP_CHANNELS, &channels);//音频设备通道
    ioctl(fdsoundplay, SNDCTL_DSP_SETFRAGMENT, &setting);//采样缓冲区

    while(flag_play_audio)
    {
        sem_wait(&sem_play);
        //if(n > BUFFER_COUNT)
        {
            val = (last_recv_time.tv_sec  - ((pk_hdr_t*)(pReadHeader->buffer))->sec)*1000 
                + (last_recv_time.tv_usec - ((pk_hdr_t*)(pReadHeader->buffer))->usec)/1000;

            printf("play NO=%5d\n", ((pk_hdr_t*)(pReadHeader->buffer))->FrameNO);
            //if(((pk_hdr_t*)(pWriteHeader->buffer))->FrameNO - ((pk_hdr_t*)(pReadHeader->buffer))->FrameNO < 3)
            //    continue;
            #if 0
            printf("play sec %ld,",    ((pk_hdr_t*)(pReadHeader->buffer))->sec) ;
            printf("usec %ld,", ((pk_hdr_t*)(pReadHeader->buffer))->usec);
            printf("val=%d,", val);
            printf("recv sec=%ld,usec=%ld\n", last_recv_time.tv_sec, last_recv_time.tv_usec);
            #endif

#if 0
            //不播放时差超过50ms的音频包
            if((val > 100) && (val < 2000))
            {
                //pthread_mutex_lock(&mutex_lock);
                printf("(%ld-%ld)*1000+(%ld-%ld)=%d\n", 
                    last_recv_time.tv_sec, ((pk_hdr_t*)(pReadHeader->buffer))->sec,
                    last_recv_time.tv_usec, ((pk_hdr_t*)(pReadHeader->buffer))->usec, val);

               // pReadHeader = pReadHeader->pNext->pNext->pNext->pNext->pNext->pNext;
                pReadHeader = pWriteHeader;
                n = 0;
                AUDIOBUFFER *p = pWriteHeader->pNext;
                for(i=0;i<BUFFERNODECOUNT-1;i++)
                {
                    memset(p->buffer, 0, sizeof(p->buffer));
                    p = p->pNext;
                }
                //pthread_mutex_unlock(&mutex_lock);
                continue;
            }
#endif

            if(write(fdsoundplay, &(pReadHeader->buffer[sizeof(pk_hdr_t)]), sizeof(pReadHeader->buffer)-sizeof(pk_hdr_t)) < 0)
            {    
                perror("音频设备写错误\n");
            }
            else
            {
                pthread_mutex_lock(&mutex_lock);
#if 0
                last_play_time.tv_sec  = ((pk_hdr_t*)(pReadHeader->buffer))->sec;
                last_play_time.tv_usec = ((pk_hdr_t*)(pReadHeader->buffer))->usec;
#endif
#if DEBUG_SAVE_PLAY_PCM
                fwrite(&(pReadHeader->buffer[sizeof(pk_hdr_t)]), sizeof(pReadHeader->buffer)-sizeof(pk_hdr_t), 1, fp);
#endif
                (((pk_hdr_t*)(pReadHeader->buffer))->valid = 0);
                pReadHeader = pReadHeader->pNext;
                n--;
                pthread_mutex_unlock(&mutex_lock);
            }


        }
        //fwrite(buffer, sizeof(buffer), 1, fprecord);
    }
    close(fdsoundplay);
#elif (SOUND_INTERFACE == SOUND_ALSA)
    /* Open PCM device for playback. */
    rc = snd_pcm_open(&handle, "hw:0,0", 
                    SND_PCM_STREAM_PLAYBACK, 0);
    if (rc < 0) {
    fprintf(stderr, 
            "unable to open pcm device: %s\n",
            snd_strerror(rc));
    exit(1);
    }

    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it in with default values. */
    snd_pcm_hw_params_any(handle, params);

    /* Set the desired hardware parameters. */

    /* Interleaved mode */
    snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);

    /* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

    /* Two channels (stereo) */
    snd_pcm_hw_params_set_channels(handle, params, CHANNELS);

    /* 44100 bits/second sampling rate (CD quality) */
    val = SAMPLERATE;
    snd_pcm_hw_params_set_rate_near(handle, params, 
                                  &val, &dir);

    /* Set period size to 32 frames. */
    frames = SAMPLES_FOR_EACH_TIME;
    snd_pcm_hw_params_set_period_size_near(handle,
                              params, &frames, &dir);

    /* Write the parameters to the driver */
    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0) {
    fprintf(stderr, 
            "unable to set hw parameters: %s\n",
            snd_strerror(rc));
    exit(1);
    }

    /* Use a buffer large enough to hold one period */
    snd_pcm_hw_params_get_period_size(params, &frames,
                                    &dir);
#if 0                                    
    size = frames * sizeof(short) * channels; /* 2 bytes/sample, 2 channels */
    buffer = (char *) malloc(size);
#endif
    /* We want to loop for 5 seconds */
    snd_pcm_hw_params_get_period_time(params, &val, &dir); 
                                    
    while(flag_play_audio)
    {
        sem_wait(&sem_recv);
#if 0        
        rc = read(0, buffer, size);
        if (rc == 0) {
          fprintf(stderr, "end of file on input\n");
          break;
        } else if (rc != size) {
          fprintf(stderr,
                  "short read: read %d bytes\n", rc);
        }
#endif        
        //traceprintf("播放\n");
        if(n > BUFFER_COUNT)
        {
        rc = snd_pcm_writei(handle, pReadHeader->buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means underrun */
          fprintf(stderr, "underrun occurred\n");
          snd_pcm_prepare(handle);
        } else if (rc < 0) 
        {
            fprintf(stderr, "error from writei: %s\n", snd_strerror(rc));
                    
            rc = xrun_recovery(handle, rc);             
            if (rc < 0) 
            {
                printf("Write error: %s\n", snd_strerror(rc));
                //return -1;
            }                   
        }  else if (rc != (int)frames) {
          fprintf(stderr, 
                  "short write, write %d frames\n", rc);
        } 
        
#if DEBUG_SAVE_PLAY_PCM
        fwrite(pReadHeader->buffer, sizeof(pReadHeader->buffer), 1, fp);
#endif
        pReadHeader = pReadHeader->pNext;
        n--;  
        }             
    }                                    
#endif

#if DEBUG_SAVE_PLAY_PCM
    fclose(fp);
#endif
    printf("音频播放线程已经关闭 audio play thread is closed\n");
}

//清除音频播放线程
void remove_play_audio(void)
{
    sem_post(&sem_recv);
    flag_play_audio = 0;
    usleep(40*1000);
    pthread_cancel(thread_play_audio);
}

#define RUNMODE_SERVER          0  //接收端
#define RUNMODE_CLIENT          1  //发送端
int main(int argc, char **argv)
{
    int runmode;//运行模式
    int cmd;
    FILE *fprecord = NULL;
    int i, j;
    int  iret1, iret2, result;
    int port[10]={0, };
    
    if(argc <= 1)
    {
	printf("参数个数错误\n");
	return -1;
    }
    
    if(strcmp("capture", argv[1])==0)
    {
	printf("客户端模式\n");
	runmode = RUNMODE_CLIENT;
	if(argc != 4)
	{
	    printf("客户模式参数格式不正确: tape capture 192.168.2.100 20000\n");
	    return -1;
	}
	else
	{
	    printf("服务器ip  : %s\n", argv[2]);
	    printf("服务器port: %s\n", argv[3]);
	    serverport = atoi(argv[3]);
	    memcpy(serverip, argv[2], strlen(argv[2]));
	}
    }
    else if(strcmp("play", argv[1])==0)
    {
	    printf("服务端模式\n");
	    runmode = RUNMODE_SERVER;
    }
    else
    {
	    printf("未知的模式\n");
	    return -1;
    }


    pthread_mutex_init(&mutex_lock, NULL);
    pthread_mutex_init(&mutex_capture, NULL);    
    
    for(i=0;i<BUFFERNODECOUNT-1;i++)
    {
        audiobuffer[i].pNext = &audiobuffer[i+1];
    }
    audiobuffer[BUFFERNODECOUNT-1].pNext = &audiobuffer[0];
    pWriteHeader = &audiobuffer[0];
    pReadHeader  = &audiobuffer[0];

    for(j=0;j<MAX_THREAD_COUNT;j++)
    {
        for(i=0;i<BUFFERNODECOUNT-1;i++)
        {
            recvbuffer[j][i].pNext = &recvbuffer[j][i+1];
        }
        recvbuffer[j][BUFFERNODECOUNT-1].pNext = &recvbuffer[j][0];
        pWriteHdrRecv[j] = &recvbuffer[j][0];
        pReadHdrRecv[j]  = &recvbuffer[j][0];
        package_count[j] = 0;
    }
    //fprecord = fopen("r.pcm", "wb");

    //fclose(fprecord);
    printf("SAMPLERATE/1000*READMSFORONCE*sizeof(short)=%d\n", SAMPLERATE/1000*READMSFORONCE*sizeof(short));

    flag_capture_audio = 1;
    flag_play_audio    = 1;
    flag_network_send  = 1;
    flag_network_recv  = 1;
    
    if(runmode == RUNMODE_CLIENT)
    {
        result = sem_init(&sem_capture, 0, 0);
        if (result != 0)
        {
            perror("Semaphore capture initialization failed");
        }

        printf("创建发送与采集线程\n");
	    iret1 = pthread_create(&thread_capture_audio, NULL, capture_audio_thread, (void*) NULL);
	    iret1 = pthread_create(&thread_network_send, NULL, network_send_thread, (void*) NULL);
        //pthread_join(thread_capture_audio, NULL);
        //pthread_join(thread_network_send, NULL);
    }
    else if(runmode == RUNMODE_SERVER)
    {
        result = sem_init(&sem_recv, 0, 0);
        if (result != 0)
        {
            perror("Semaphore recv initialization failed");
        }

        result = sem_init(&sem_play, 0, 0);
        if (result != 0)
        {
            perror("Semaphore play initialization failed");
        }
        
        printf("创建播放与接收线程\n");
	    iret2 = pthread_create(&thread_play_audio, NULL, play_audio_thread, (void*) NULL);  
	    iret2 = pthread_create(&thread_mix_audio, NULL, mix_audio_thread, (void*) NULL);  
	    for(i=0;i<MAX_THREAD_COUNT;i++)
	    {
	        port[i] = UDP_BIND_PORT_START + i;//端口号
	        iret2 = pthread_create(&thread_network_recv, NULL, network_recv_thread, &(port[i]));
	    }
        //pthread_join(thread_play_audio, NULL);
        //pthread_join(thread_network_recv, NULL);
    }

    while(programrun)
    {
        usleep(1000);
        cmd = getchar();
        switch(cmd)
        {
            case 'A':
                printf("A");
                break;
            case 'Q':
                programrun = 0;
            default:
                break;
        }

    }

    usleep(40*1000);

    if(runmode == RUNMODE_CLIENT)
    {
	    remove_capture_audio();
	    remove_network_send();
    }
    else if(runmode == RUNMODE_SERVER)
    {
        printf("清除发送线程\n");
        remove_play_audio();
        remove_network_recv();
    }
}

